#  参考来源：zlgcan_demo.py

import threading

###############################################################################


class PeriodSendThread(object):

    def __init__(self, period_func, name=None, args=[], **kwargs):
        if name:
            self._thread = threading.Thread(target=self._run, name=name)
        else:
            self._thread = threading.Thread(target=self._run)

        self._function = period_func
        self._args = args
        self._kwargs = kwargs
        self._period = 0
        self._event = threading.Event()
        self._period_event = threading.Event()
        self._terminated = False

    def join(self):
        # 手动调用join，等待线程结束
        self._thread.join()

    def start(self):
        self._thread.start()

    def stop(self):
        # 因为需要执行_run中的break，所以需要设置_terminated为True
        # 然后设置_event，让_run中的外层while循环退出通过self._event.wait()阻塞
        # 否则_run中的while循环会一直在阻塞
        self._terminated = True
        self._event.set()
        # self._thread.join()

    def send_start(self, period):
        self._period = period
        # start以后，_run中的while循环会通过self._event.wait()阻塞
        # 此处通过send_start设置_event，让_run中的self._event.wait()通过，继续执行
        # 从而执行self._function(*self._args, **self._kwargs)
        # 并且进入内层的while循环，等待wait的超时时间，循环执行self._function(*self._args, **self._kwargs)
        # 直到self._period_event.set()，内层的while循环退出，再次进入外层的while循环，阻塞在self._event.wait()，等待self._event.set()
        self._event.set()

    def send_stop(self):
        self._period_event.set()

    def _run(self):
        while True:
            self._event.wait()
            self._event.clear()
            if self._terminated:
                break
            self._function(*self._args, **self._kwargs)
            # wait函数的参数是超时时间，到时间会自动返回，不需要其他线程的协助
            # 此处是先阻塞，等待超时，超时后会返回，根据返回的值判断是否继续循环
            while not self._period_event.wait(self._period):
                self._function(*self._args, **self._kwargs)
            self._period_event.clear()
###############################################################################


def main():
    def func1(a, b, key1, key2):
        print("func1", a, b, key1, key2)
    pst = PeriodSendThread(func1, [12], {'b': '666', 'key1': 1, 'key2': 2})

    pst.start()
    pst.send_start(1)
    # FIXME: 此处不是必须得，根据具体情况看主线程是否需要等待子线程结束
    pst.join()
    pass


if __name__ == '__main__':
    main()
